﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Management.Automation;
using System.Data.SqlClient;

using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.PowerShell;

namespace Mystery.SharePoint.PowerShell
{
	[Cmdlet("Run", "SPMDatabaseScript")]
	public class RunDatabaseScriptCmdlet : SPCmdlet
	{
		/// <summary>
		/// The name of the server we are running the script agains
		/// </summary>
		[Parameter(Mandatory = true)]
		public string DataSource { get; set; }
		/// <summary>
		/// The name of the database we are running the script agains
		/// </summary>
		[Parameter(Mandatory = true)]
		public string InitialCatalog { get; set; }
		/// <summary>
		/// The name of the script file
		/// </summary>
		[Parameter(Mandatory = true)]
		public string ScriptFile { get; set; }
		/// <summary>
		/// Token information used to replace content in the script file
		/// </summary>
		[Parameter(Mandatory = false)]
		public string Tokens { get; set; }

		protected override void  InternalProcessRecord()
		{
 			SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
            builder.DataSource = this.DataSource;
            builder.InitialCatalog = this.InitialCatalog;
            builder.IntegratedSecurity = true;

			using (SqlConnection connection = new SqlConnection(builder.ToString()))
            {
				base.Host.UI.WriteLine(
					string.Format(null, "Running script file: {0}", this.ScriptFile));
				base.Host.UI.WriteLine(
					string.Format(null, "Using tokens: {0}", this.Tokens));

				connection.Open();
				string content = File.ReadAllText(this.ScriptFile);
                string commands = Utils.ReplaceTokens(content, this.Tokens);

                ExecuteCommands(connection, commands); 
            }
		}

        /// <summary>
        /// Executes a number of database commands over the specified connection
        /// </summary>
        /// <param name=`"connection`">The connection to use</param>
        /// <param name=`"commands`">The commands to execute</param>
        private static void ExecuteCommands(SqlConnection connection, string commands)
        {
            StringReader reader = new StringReader(commands);
            SqlCommand command = new SqlCommand(null, connection);
            StringBuilder commandText = null;
            string line = null;

            do
            {
                line = reader.ReadLine();
                bool execute = false;

                if ((line == null) ||
                    (string.Compare(line.Trim(), "GO", true) == 0))
                {
                    execute = true;
                }
                else
                {
                    if (commandText == null)
                    {
                        commandText = new StringBuilder();
                    }
                    if (commandText.Length > 0)
                    {
                        commandText.Append(Environment.NewLine);
                    }
                    // don't execute sqlcmd statements and print statements
                    if ((line.StartsWith(":") == false) &&
                        (line.StartsWith("PRINT") == false))
                    {
                        commandText.AppendFormat("{0}{1}", line, Environment.NewLine);
                    }
                }

                if ((execute == true) &&
                    (commandText != null) &&
                    (commandText.Length > 0))
                {
                    command.CommandText = commandText.ToString();
                    command.CommandTimeout = 900;
                    command.ExecuteNonQuery();
                    commandText = null;
                }

            } while (line != null);
        }
	}
}
